package com.nan.gbd.library.utils;


import android.text.TextUtils;

import com.nan.gbd.library.GB28181ControlManager;
import com.nan.gbd.library.codec.configuration.Configuration;
import com.nan.gbd.library.sip.RecordBean;
import com.nan.gbd.library.sip.account.DevConfig;
import com.nan.gbd.library.sip.account.SipConfig;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Author: zhuohf
 * Version: V0.1 2018/2/19
 */
public class AccountConfig {

    public static final String FORMAT_CONFIG_ACCOUNT = "account/gb28181_config.json";
    private static volatile AccountConfig instance;
    private static int mLocalPort = 15062;

    private SipConfig sipConfigNow;
    private DevConfig devConfigNow;

    public static AccountConfig getInstance() {
        if (null == instance) {
            synchronized (AccountConfig.class) {
                if (null == instance) {
                    instance = new AccountConfig();
                }
            }
        }
        return instance;
    }

    public void initConfig() {
        String content = readAssetsFile(FORMAT_CONFIG_ACCOUNT);
        initGB28181Config(content);
    }

    /**
     * 读取Assets
     *
     * @param fileName
     * @return
     */
    private String readAssetsFile(String fileName) {
        try {
            InputStream inputStream=  Configuration.get().getmContext().getResources().getAssets().open(fileName);
            String content = readInputStream(inputStream);
            return content;
        } catch (IOException e) {
            e.printStackTrace();
            Logger.w("Not have save the default config file.");
            return "";
        }
    }

    /**
     * 读取流
     *
     * @param inputStream
     * @return
     */
    private String readInputStream(InputStream inputStream) {
        String jsonStr = "";
        try {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];

            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                byteOut.write(buffer, 0, len);
            }

            jsonStr = byteOut.toString(StandardCharsets.UTF_8.name());
            byteOut.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return jsonStr;
        } finally {
            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return jsonStr;
    }

    /**
     * 获取国标配置文件
     *
     * @return
     */
    public SipConfig initGB28181Config(String sipConfigStr) {
        if (TextUtils.isEmpty(sipConfigStr)) {
            return null;
        }
        SipConfig sipConfig = fromJson(sipConfigStr);
        this.sipConfigNow = sipConfig;
        this.devConfigNow = sipConfig.getDevConfig();
        return sipConfig;
    }

    /**
     * 配置文件更新
     */
    public void update(String sipConfigStr) {
        Logger.e("配置文件有更新:\n" + sipConfigStr);
        if (TextUtils.isEmpty(sipConfigStr)) return;
        SipConfig sipConfigNew = fromJson(sipConfigStr);
        if (sipConfigNew == null) return;
        if (sipConfigNow == null) {
            this.sipConfigNow = sipConfigNew;
            GB28181ControlManager.getInstance().reinit();
            return;
        }
        //如果服务器信息发生改变,则重新连接服务器
        if (!TextUtils.equals(sipConfigNew.getServerDomain(), sipConfigNow.getServerDomain()) ||
                !TextUtils.equals(sipConfigNew.getServerId(), sipConfigNow.getServerId()) ||
                !TextUtils.equals(sipConfigNew.getServerIp(), sipConfigNow.getServerIp()) ||
                !TextUtils.equals(sipConfigNew.getPassword(), sipConfigNow.getPassword()) ||
                !TextUtils.equals(sipConfigNew.getUserId(), sipConfigNow.getUserId()) ||
                !TextUtils.equals(sipConfigNew.getVideoChannel(), sipConfigNow.getVideoChannel()) ||
                !TextUtils.equals(sipConfigNew.getAlarmChannel(), sipConfigNow.getAlarmChannel()) ||
                !TextUtils.equals(sipConfigNew.getAudioChannel(), sipConfigNow.getAudioChannel()) ||
                sipConfigNew.getServerPort() != sipConfigNow.getServerPort()) {
            Logger.e("发现服务器相关参数有更新...");
            this.sipConfigNow = sipConfigNew;
            GB28181ControlManager.getInstance().reinit();
        }
        //判断设备参数是否发生改变
        DevConfig devConfig = sipConfigNew.getDevConfig();
        if (devConfig == null) return;
        if (devConfigNow == null) {
            this.devConfigNow = devConfig;
            return;
        }
        if (!TextUtils.equals(devConfig.getProtocol(), devConfigNow.getProtocol()) ||
                (devConfig.getExpiredVideoDay() != devConfigNow.getExpiredVideoDay()) ||
                (devConfig.getHeartbeatCount() != devConfigNow.getHeartbeatCount()) ||
                (devConfig.getHeartbeatInterval() != devConfigNow.getHeartbeatInterval()) ||
                (devConfig.getMaxDuration() != devConfigNow.getMaxDuration()) ||
                (devConfig.getRegExpiry() != devConfigNow.getRegExpiry())) {
            Logger.e("发现devConfig参数有更新...");
            this.devConfigNow = devConfig;
        }
    }

    public SipConfig getSipConfig() {
        return sipConfigNow;
    }

    public DevConfig getDevConfig() {
        return devConfigNow;
    }


    private SipConfig fromJson(String json) {
        if (TextUtils.isEmpty(json)) return null;
        SipConfig sipConfig = null;
        try {
            JSONObject configJSON = new JSONObject(json);
            sipConfig = new SipConfig(configJSON);
            return sipConfig;
        } catch (JSONException e) {
            Logger.e(e);
        }
        return null;
    }


    /**
     * 获取录制文件存放地址
     *
     * @return
     */
    public static String getRecordPath() {
        return Configuration.get().getRecordPath();
    }

    /**
     * 初始化本地设备信令绑定端口号
     *
     * @return 本地端口号
     */
    public static int initLocalPort() {
        if (mLocalPort != 0) {
            return mLocalPort;
        }
        try (ServerSocket serverSocket = new ServerSocket(0)) {
            mLocalPort = serverSocket.getLocalPort();
        } catch (IOException e) {
            mLocalPort = 15062;
        }
        return mLocalPort;
    }


    /**
     * 获取录制视频的最大时长
     *
     * @return
     */
    public int getMaxDuration() {
        if (devConfigNow != null) {
            return devConfigNow.getMaxDuration();
        }
        return DevConfig.MAX_DURATION;
    }

    /**
     * 获取本地存储空间最少不低于
     *
     * @return
     */
    public int getFreeStorageSpace() {
        if (devConfigNow != null) {
            return devConfigNow.getFreeStorageSpace();
        }
        return DevConfig.FREE_STORAGE_SPACE;
    }

    /**
     * 获取录制视频最大存储时间
     *
     * @return
     */
    public int getExpiredVideoDay() {
        if (devConfigNow != null) {
            return devConfigNow.getExpiredVideoDay();
        }
        return DevConfig.EXPIRED_VIDEO_DAY;
    }


    /**
     * 检查存储空间是否满足存储需求,存储空间最少必须大于等于50M
     * 存储空间不足:
     * 1.检查是否存在过期的视频记录,如果还是不满足存储条件继续2;
     * 2.删除本地最早保存的视频文件
     */
    public boolean checkStorage() {
        boolean isWrita = Configuration.get().isWritable();
        if (isWrita) {
            Logger.e("当前存储空间充足");
            return true;
        }
        Logger.e("当前存储空间不足,先检查是否有需要清理的文件");
        checkExpiredVideo();
        isWrita = Configuration.get().isWritable();
        if (isWrita) return true;

        Logger.e("当前存储空间还是不足,删除最久的那个文件");
        RecordBean recordBean = getLongestRecord();
        if (recordBean != null) {
            boolean isDel = detelVideoRecord(recordBean);
            Logger.e("删除最久的那个文件,删除结果:" + isDel);
        }
        isWrita = Configuration.get().isWritable();
        if (isWrita)
            return true;
        else
            return checkStorage();
    }

    /**
     * 检查本地录制视频是否已过期
     */
    public void checkExpiredVideo() {
        List<RecordBean> recordBeans = SpRecordUtils.getRecordBeanList();
        long expiredVideoDayMs = getExpiredVideoDay() * 24 * 60 * 60;
        if (recordBeans == null || recordBeans.size() == 0) return;
        int expiredNum = 0;
        for (RecordBean recordBean : recordBeans) {
            long currentTime = System.currentTimeMillis() / 1000;
            //如果文件超过过期时间,删除该文件
            if (currentTime - recordBean.getStartTime() > expiredVideoDayMs) {
                boolean isDel = detelVideoRecord(recordBean);
                if (isDel) expiredNum++;
            }
        }
        Logger.e("清理过期文件完成,总共清理:" + expiredNum + "条");

    }

    /**
     * 获取保存最久的那个文件
     *
     * @return
     */
    private RecordBean getLongestRecord() {
        List<RecordBean> recordBeans = SpRecordUtils.getRecordBeanList();
        if (recordBeans == null || recordBeans.size() == 0) {
            return null;
        }
        Collections.sort(recordBeans, new Comparator<RecordBean>() {
            @Override
            public int compare(RecordBean o1, RecordBean o2) {
                return (int) (o1.getStartTime() - o2.getStartTime());
            }
        });
        return recordBeans.get(0);
    }

    /**
     * 删除视频文件及相对应的缓存记录
     *
     * @param recordBean
     * @return
     */
    private boolean detelVideoRecord(RecordBean recordBean) {
        boolean isSuccess = false;
        File file = new File(recordBean.getPath());
        if (file.exists()) {
            isSuccess = file.delete();
            if (isSuccess) {
                //删除文件缓存记录
                Logger.e("清理掉一条文件,文件路径:" + recordBean.getPath());
                SpRecordUtils.removeVideoRecordKey(String.valueOf(recordBean.getEndTime()));
                SpRecordUtils.removeKey(String.valueOf(recordBean.getEndTime()));

                //判断该文件夹是否是空文件夹,是则删除
                boolean isdel = cleanNullDirectory(recordBean.getAddress());
                if (!isdel) {
                    Logger.e("清理空的文件夹失败,文件夹地址:" + recordBean.getAddress());
                }
            }
        }
        return isSuccess;
    }

    /**
     * 清理空的文件夹
     *
     * @param directory
     */
    private boolean cleanNullDirectory(String directory) {
        File superFile = new File(directory);
        boolean isSuccess = false;
        if (superFile.exists() && superFile.isDirectory()) {
            int fileNum = superFile.listFiles().length;
            if (fileNum == 0) {
                isSuccess = superFile.delete();
            }
        }
        return isSuccess;
    }


}
